﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Xml;
using System.Security.Cryptography;
using System.Text;
using System.Web.Script.Serialization;
using System.Web.UI;
using System.Net;
using System.IO;

namespace WxPayApi
{
	public class Notify
	{
		public SortedDictionary<string, object> GetNotifyData()
		{
			SortedDictionary<string, object> result = new SortedDictionary<string, object>();

			#region 接收从微信后台POST过来的数据
			System.IO.Stream s = HttpContext.Current.Request.InputStream;
			int count = 0;
			byte[] buffer = new byte[1024];
			StringBuilder builder = new StringBuilder();
			while ((count = s.Read(buffer, 0, 1024)) > 0)
			{
				builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
			}
			s.Flush();
			s.Close();
			s.Dispose();
			#endregion

			#region 转换数据格式
			string xml = builder.ToString();
			if (string.IsNullOrEmpty(xml))
			{
				throw new Exception("异步通知接收到的xml串为空!");
			}

			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.XmlResolver = null;
			xmlDoc.LoadXml(xml);
			XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
			XmlNodeList nodes = xmlNode.ChildNodes;
			foreach (XmlNode xn in nodes)
			{
				XmlElement xe = (XmlElement)xn;
				result[xe.Name] = xe.InnerText;
			}
			#endregion

			return result;
		}

		public void Verify(Dictionary<string, string> config, SortedDictionary<string, object> array)
		{
			//验证签名
			PayData data = new PayData(config, array);
			if (array["return_code"].ToString() == "SUCCESS")
				data.CheckSign();

			//检查支付结果中transaction_id是否存在
			if (!data.IsSet("transaction_id"))
			{
				throw new Exception("支付结果中微信订单号不存在");
			}

			//查询订单，判断订单真实性
			PayData input = new PayData(config);
			input.SetValue("transaction_id", data.GetValue("transaction_id"));
			input.SetValue("appid", config["APPID"]);
			input.SetValue("mch_id", config["MCHID"]);
			input.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));
			input.SetValue("sign", input.MakeSign());

			PayData res = OrderQuery(input);
			if (res.GetValue("return_code").ToString() != "SUCCESS" || res.GetValue("result_code").ToString() != "SUCCESS")
			{
				File.AppendAllText(HttpContext.Current.Server.MapPath("~/log.txt"), "\r\n\r\n=============================================\r\n" + res.ToPrintStr() + "\r\n=============================================\r\n\r\n");
				throw new Exception("订单查询失败");
			}
		}

		/**
		*    
		* 查询订单
		* @param WxPayData inputObj 提交给查询订单API的参数
		* @param int timeOut 超时时间
		* @throws WxPayException
		* @return 成功时返回订单查询结果，其他抛异常
		*/
		public PayData OrderQuery(PayData inputObj, int timeOut = 6)
		{
			//检测必填参数
			if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
			{
				throw new Exception("订单查询接口中，out_trade_no、transaction_id至少填一个！");
			}

			//
			if (!inputObj.IsSet("appid") || !inputObj.IsSet("mch_id") || !inputObj.IsSet("nonce_str") || !inputObj.IsSet("sign"))
			{
				throw new Exception("订单查询接口中，必须设置appid、mch_id,nonce_str,sign！");
			}

			string xml = inputObj.ToXml();
			string url = "https://api.mch.weixin.qq.com/pay/orderquery";
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
			request.Method = "POST";
			request.Timeout = 6 * 1000;
			request.ContentType = "text/xml";
			byte[] buffer = System.Text.Encoding.UTF8.GetBytes(xml);
			request.ContentLength = buffer.Length;

			//往服务器写入数据
			Stream reqStream = request.GetRequestStream();
			reqStream.Write(buffer, 0, buffer.Length);
			reqStream.Close();

			//获取服务端返回
			HttpWebResponse response = (HttpWebResponse)request.GetResponse();
			StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
			string resultStr = sr.ReadToEnd().Trim();
			sr.Close();

			//将xml格式的数据转化为对象以返回
			inputObj.Clear();
			inputObj.FromXml(resultStr);

			return inputObj;
		}

		public string BuildFail(string message)
		{
			PayData data = new PayData();
			data.SetValue("return_code", "FAIL");
			data.SetValue("return_msg", message);
			//HttpContext.Current.Response.Write(data.ToXml());
			//HttpContext.Current.Response.End();
			return data.ToXml();
		}
		public string BuildSuccess()
		{
			PayData res = new PayData();
			res.SetValue("return_code", "SUCCESS");
			res.SetValue("return_msg", "OK");
			//HttpContext.Current.Response.Write(res.ToXml());
			//HttpContext.Current.Response.End();
			return res.ToXml();
		}
	}
}